package com.kexio.file.controller;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kexio.auth.annotation.Audit;
import com.kexio.auth.annotation.RateLimit;
import com.kexio.auth.annotation.RequiresPermission;
import com.kexio.common.dto.Result;
import com.kexio.file.entity.ShareLink;
import com.kexio.file.service.ShareLinkService;
import com.kexio.file.vo.ShareLinkVO;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;

/**
 * 文件分享链接控制器
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
@Tag(name = "文件分享管理", description = "文件分享链接相关接口")
@RestController
@RequestMapping("/file/share")
// 类级可选权限：方法上已精细化控制
public class ShareLinkController {

    @Autowired
    private ShareLinkService shareLinkService;

    /**
     * 创建分享链接
     */
    @Operation(summary = "创建分享链接", description = "为指定文件创建分享链接")
    @PostMapping("/create")
    @RequiresPermission("file:share:create")
    @Audit(value = "创建文件分享链接", module = "file")
    @RateLimit(key = "file:share:create", count = 10, time = 1, timeUnit = TimeUnit.MINUTES)
    public Result<ShareLinkVO> createShareLink(@RequestBody CreateShareLinkRequest request) {
        try {
            ShareLinkVO shareLink = shareLinkService.createShareLink(
                    request.getFileId(),
                    request.getShareType(),
                    request.getPassword(),
                    request.getValidUntil(),
                    request.getMaxAccessCount(),
                    request.getMaxDownloadCount(),
                    request.getDescription()
            );
            return Result.success(shareLink);
        } catch (Exception e) {
            return Result.error("创建分享链接失败: " + e.getMessage());
        }
    }

    /**
     * 根据分享码获取分享信息（公开接口）
     */
    @Operation(summary = "获取分享信息", description = "根据分享码获取分享链接信息")
    @GetMapping("/info/{shareCode}")
    @Audit(value = "查看文件分享信息", module = "file")
    @RateLimit(key = "file:share:info", count = 60, time = 1, timeUnit = TimeUnit.MINUTES, limitType = RateLimit.LimitType.IP)
    public Result<ShareLinkVO> getShareInfo(
            @Parameter(description = "分享码") @PathVariable String shareCode) {
        try {
            ShareLinkVO shareLink = shareLinkService.getByShareCode(shareCode);
            if (shareLink == null) {
                return Result.error("分享链接不存在");
            }
            return Result.success(shareLink);
        } catch (Exception e) {
            return Result.error("获取分享信息失败: " + e.getMessage());
        }
    }

    /**
     * 验证分享链接访问权限（公开接口）
     */
    @Operation(summary = "验证分享访问", description = "验证分享链接的访问权限")
    @PostMapping("/validate")
    @Audit(value = "验证分享访问", module = "file")
    @RateLimit(key = "file:share:validate", count = 60, time = 1, timeUnit = TimeUnit.MINUTES, limitType = RateLimit.LimitType.IP)
    public Result<ShareLinkVO> validateShareAccess(
            @RequestBody ValidateShareRequest request,
            HttpServletRequest httpRequest) {
        try {
            String clientIp = getClientIpAddress(httpRequest);
            ShareLinkVO shareLink = shareLinkService.validateShareAccess(
                    request.getShareCode(),
                    request.getPassword(),
                    clientIp
            );
            
            // 记录访问
            shareLinkService.recordAccess(request.getShareCode(), clientIp);
            
            return Result.success(shareLink);
        } catch (Exception e) {
            return Result.error("访问验证失败: " + e.getMessage());
        }
    }

    /**
     * 记录分享下载（公开接口）
     */
    @Operation(summary = "记录分享下载", description = "记录分享链接的下载行为")
    @PostMapping("/download/{shareCode}")
    @Audit(value = "分享链接下载", module = "file")
    @RateLimit(key = "file:share:download", count = 120, time = 1, timeUnit = TimeUnit.MINUTES, limitType = RateLimit.LimitType.IP)
    public Result<Void> recordDownload(
            @Parameter(description = "分享码") @PathVariable String shareCode,
            HttpServletRequest httpRequest) {
        try {
            String clientIp = getClientIpAddress(httpRequest);
            boolean success = shareLinkService.recordDownload(shareCode, clientIp);
            if (success) {
                return Result.success();
            } else {
                return Result.error("记录下载失败");
            }
        } catch (Exception e) {
            return Result.error("记录下载失败: " + e.getMessage());
        }
    }

    /**
     * 获取文件的所有分享链接
     */
    @Operation(summary = "获取文件分享列表", description = "获取指定文件的所有分享链接")
    @GetMapping("/list/{fileId}")
    @RequiresPermission("file:share:list")
    @Audit(value = "获取文件分享列表", module = "file")
    public Result<List<ShareLinkVO>> getShareLinks(
            @Parameter(description = "文件ID") @PathVariable String fileId) {
        try {
            List<ShareLinkVO> shareLinks = shareLinkService.getShareLinksByFileId(fileId);
            return Result.success(shareLinks);
        } catch (Exception e) {
            return Result.error("获取分享列表失败: " + e.getMessage());
        }
    }

    /**
     * 获取文件的有效分享链接
     */
    @Operation(summary = "获取有效分享链接", description = "获取指定文件的有效分享链接")
    @GetMapping("/valid/{fileId}")
    @RequiresPermission("file:share:view")
    @Audit(value = "获取有效分享链接", module = "file")
    public Result<List<ShareLinkVO>> getValidShareLinks(
            @Parameter(description = "文件ID") @PathVariable String fileId) {
        try {
            List<ShareLinkVO> shareLinks = shareLinkService.getValidShareLinks(fileId);
            return Result.success(shareLinks);
        } catch (Exception e) {
            return Result.error("获取有效分享链接失败: " + e.getMessage());
        }
    }

    /**
     * 获取用户创建的分享链接
     */
    @Operation(summary = "获取用户分享列表", description = "获取当前用户创建的分享链接")
    @GetMapping("/my")
    @RequiresPermission("file:share:my")
    @Audit(value = "获取我的分享链接列表", module = "file")
    public Result<Page<ShareLinkVO>> getUserShareLinks(
            @Parameter(description = "页码") @RequestParam(defaultValue = "1") Long current,
            @Parameter(description = "每页数量") @RequestParam(defaultValue = "10") Long size) {
        try {
            // TODO: 从AuthContextUtils获取当前用户ID
            String creatorId = "current-user-id";
            
            Page<ShareLink> page = new Page<>(current, size);
            Page<ShareLinkVO> result = shareLinkService.getUserShareLinks(creatorId, page);
            return Result.success(result);
        } catch (Exception e) {
            return Result.error("获取用户分享列表失败: " + e.getMessage());
        }
    }

    /**
     * 更新分享链接
     */
    @Operation(summary = "更新分享链接", description = "更新分享链接的配置信息")
    @PutMapping("/{shareId}")
    @RequiresPermission("file:share:update")
    @Audit(value = "更新文件分享链接", module = "file")
    public Result<Void> updateShareLink(
            @Parameter(description = "分享ID") @PathVariable String shareId,
            @RequestBody UpdateShareLinkRequest request) {
        try {
            boolean success = shareLinkService.updateShareLink(
                    shareId,
                    request.getShareType(),
                    request.getPassword(),
                    request.getValidUntil(),
                    request.getMaxAccessCount(),
                    request.getMaxDownloadCount(),
                    request.getDescription()
            );
            if (success) {
                return Result.success();
            } else {
                return Result.error("更新分享链接失败");
            }
        } catch (Exception e) {
            return Result.error("更新分享链接失败: " + e.getMessage());
        }
    }

    /**
     * 禁用分享链接
     */
    @Operation(summary = "禁用分享链接", description = "禁用指定的分享链接")
    @PutMapping("/disable/{shareId}")
    @RequiresPermission("file:share:disable")
    @Audit(value = "禁用文件分享链接", module = "file")
    public Result<Void> disableShareLink(
            @Parameter(description = "分享ID") @PathVariable String shareId) {
        try {
            boolean success = shareLinkService.disableShareLink(shareId);
            if (success) {
                return Result.success();
            } else {
                return Result.error("禁用分享链接失败");
            }
        } catch (Exception e) {
            return Result.error("禁用分享链接失败: " + e.getMessage());
        }
    }

    /**
     * 启用分享链接
     */
    @Operation(summary = "启用分享链接", description = "启用指定的分享链接")
    @PutMapping("/enable/{shareId}")
    @RequiresPermission("file:share:enable")
    @Audit(value = "启用文件分享链接", module = "file")
    public Result<Void> enableShareLink(
            @Parameter(description = "分享ID") @PathVariable String shareId) {
        try {
            boolean success = shareLinkService.enableShareLink(shareId);
            if (success) {
                return Result.success();
            } else {
                return Result.error("启用分享链接失败");
            }
        } catch (Exception e) {
            return Result.error("启用分享链接失败: " + e.getMessage());
        }
    }

    /**
     * 删除分享链接
     */
    @Operation(summary = "删除分享链接", description = "删除指定的分享链接")
    @DeleteMapping("/{shareId}")
    @RequiresPermission("file:share:delete")
    @Audit(value = "删除文件分享链接", module = "file")
    public Result<Void> deleteShareLink(
            @Parameter(description = "分享ID") @PathVariable String shareId) {
        try {
            boolean success = shareLinkService.deleteShareLink(shareId);
            if (success) {
                return Result.success();
            } else {
                return Result.error("删除分享链接失败");
            }
        } catch (Exception e) {
            return Result.error("删除分享链接失败: " + e.getMessage());
        }
    }

    /**
     * 删除文件的所有分享链接
     */
    @Operation(summary = "删除文件所有分享", description = "删除指定文件的所有分享链接")
    @DeleteMapping("/all/{fileId}")
    @RequiresPermission("file:share:delete")
    @Audit(value = "删除文件所有分享链接", module = "file")
    public Result<Void> deleteAllShareLinks(
            @Parameter(description = "文件ID") @PathVariable String fileId) {
        try {
            boolean success = shareLinkService.deleteAllShareLinks(fileId);
            if (success) {
                return Result.success();
            } else {
                return Result.error("删除所有分享链接失败");
            }
        } catch (Exception e) {
            return Result.error("删除所有分享链接失败: " + e.getMessage());
        }
    }

    /**
     * 获取分享统计信息
     */
    @Operation(summary = "获取分享统计", description = "获取指定分享链接的统计信息")
    @GetMapping("/stats/{shareId}")
    @RequiresPermission("file:share:stats")
    @Audit(value = "获取分享统计", module = "file")
    public Result<Map<String, Object>> getShareStats(
            @Parameter(description = "分享ID") @PathVariable String shareId) {
        try {
            Map<String, Object> stats = shareLinkService.getShareStats(shareId);
            return Result.success(stats);
        } catch (Exception e) {
            return Result.error("获取分享统计失败: " + e.getMessage());
        }
    }

    /**
     * 获取用户分享统计
     */
    @Operation(summary = "获取用户分享统计", description = "获取当前用户的分享统计信息")
    @GetMapping("/stats/my")
    @RequiresPermission("file:share:stats")
    @Audit(value = "获取我的分享统计", module = "file")
    public Result<Map<String, Object>> getUserShareStats(
            @Parameter(description = "统计天数") @RequestParam(defaultValue = "30") Integer days) {
        try {
            // TODO: 从AuthContextUtils获取当前用户ID
            String creatorId = "current-user-id";
            
            Map<String, Object> stats = shareLinkService.getUserShareStats(creatorId, days);
            return Result.success(stats);
        } catch (Exception e) {
            return Result.error("获取用户分享统计失败: " + e.getMessage());
        }
    }

    /**
     * 获取热门分享链接
     */
    @Operation(summary = "获取热门分享", description = "获取热门分享链接列表")
    @GetMapping("/popular")
    @RequiresPermission("file:share:view")
    @Audit(value = "获取热门分享列表", module = "file")
    public Result<List<ShareLinkVO>> getPopularShareLinks(
            @Parameter(description = "限制数量") @RequestParam(defaultValue = "10") Integer limit,
            @Parameter(description = "统计天数") @RequestParam(defaultValue = "7") Integer days) {
        try {
            List<ShareLinkVO> popularLinks = shareLinkService.getPopularShareLinks(limit, days);
            return Result.success(popularLinks);
        } catch (Exception e) {
            return Result.error("获取热门分享失败: " + e.getMessage());
        }
    }

    /**
     * 批量处理过期分享链接（管理员接口）
     */
    @Operation(summary = "处理过期分享", description = "批量处理过期的分享链接")
    @PostMapping("/admin/process-expired")
    @RequiresPermission("file:share:admin")
    @Audit(value = "处理过期分享链接", module = "file")
    public Result<Integer> processExpiredLinks() {
        try {
            int processedCount = shareLinkService.processExpiredLinks();
            return Result.success(processedCount);
        } catch (Exception e) {
            return Result.error("处理过期分享链接失败: " + e.getMessage());
        }
    }

    /**
     * 批量处理访问次数达限的分享链接（管理员接口）
     */
    @Operation(summary = "处理访问达限分享", description = "批量处理访问次数已达上限的分享链接")
    @PostMapping("/admin/process-limit-reached")
    @RequiresPermission("file:share:admin")
    @Audit(value = "处理访问达限分享链接", module = "file")
    public Result<Integer> processAccessLimitReachedLinks() {
        try {
            int processedCount = shareLinkService.processAccessLimitReachedLinks();
            return Result.success(processedCount);
        } catch (Exception e) {
            return Result.error("处理访问达限分享链接失败: " + e.getMessage());
        }
    }

    // ==================== 工具方法 ====================

    /**
     * 获取客户端IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
            return xForwardedFor.split(",")[0].trim();
        }
        
        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
            return xRealIp;
        }
        
        return request.getRemoteAddr();
    }

    // ==================== 内部类 ====================

    /**
     * 创建分享链接请求
     */
    public static class CreateShareLinkRequest {
        private String fileId;
        private Integer shareType;
        private String password;
        private LocalDateTime validUntil;
        private Integer maxAccessCount;
        private Integer maxDownloadCount;
        private String description;

        // Getters and Setters
        public String getFileId() { return fileId; }
        public void setFileId(String fileId) { this.fileId = fileId; }
        public Integer getShareType() { return shareType; }
        public void setShareType(Integer shareType) { this.shareType = shareType; }
        public String getPassword() { return password; }
        public void setPassword(String password) { this.password = password; }
        public LocalDateTime getValidUntil() { return validUntil; }
        public void setValidUntil(LocalDateTime validUntil) { this.validUntil = validUntil; }
        public Integer getMaxAccessCount() { return maxAccessCount; }
        public void setMaxAccessCount(Integer maxAccessCount) { this.maxAccessCount = maxAccessCount; }
        public Integer getMaxDownloadCount() { return maxDownloadCount; }
        public void setMaxDownloadCount(Integer maxDownloadCount) { this.maxDownloadCount = maxDownloadCount; }
        public String getDescription() { return description; }
        public void setDescription(String description) { this.description = description; }
    }

    /**
     * 验证分享访问请求
     */
    public static class ValidateShareRequest {
        private String shareCode;
        private String password;

        // Getters and Setters
        public String getShareCode() { return shareCode; }
        public void setShareCode(String shareCode) { this.shareCode = shareCode; }
        public String getPassword() { return password; }
        public void setPassword(String password) { this.password = password; }
    }

    /**
     * 更新分享链接请求
     */
    public static class UpdateShareLinkRequest {
        private Integer shareType;
        private String password;
        private LocalDateTime validUntil;
        private Integer maxAccessCount;
        private Integer maxDownloadCount;
        private String description;

        // Getters and Setters
        public Integer getShareType() { return shareType; }
        public void setShareType(Integer shareType) { this.shareType = shareType; }
        public String getPassword() { return password; }
        public void setPassword(String password) { this.password = password; }
        public LocalDateTime getValidUntil() { return validUntil; }
        public void setValidUntil(LocalDateTime validUntil) { this.validUntil = validUntil; }
        public Integer getMaxAccessCount() { return maxAccessCount; }
        public void setMaxAccessCount(Integer maxAccessCount) { this.maxAccessCount = maxAccessCount; }
        public Integer getMaxDownloadCount() { return maxDownloadCount; }
        public void setMaxDownloadCount(Integer maxDownloadCount) { this.maxDownloadCount = maxDownloadCount; }
        public String getDescription() { return description; }
        public void setDescription(String description) { this.description = description; }
    }
}
